/*
 * Copyright (c) 2011-2019, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package boofcv.alg.enhance.impl;

import boofcv.struct.image.GrayF32;
import boofcv.struct.image.GrayI;
import boofcv.struct.image.GrayU8;

import javax.annotation.Generated;

//CONCURRENT_INLINE import boofcv.concurrency.BoofConcurrency;

/**
 * <p>
 * Filter based functions for image enhancement.
 * </p>
 *
 * <p>
 * DO NOT MODIFY. This code was automatically generated by GenerateImplEnhanceFilter.
 * <p>
 *
 * @author Peter Abeles
 */
@Generated("boofcv.alg.enhance.impl.GenerateImplEnhanceFilter")
public class ImplEnhanceFilter {

	public static void sharpenInner4( GrayU8 input , GrayU8 output , int minValue , int maxValue ) {
		//CONCURRENT_BELOW BoofConcurrency.loopFor(1,input.height-1,y->{
		for( int y = 1; y < input.height-1; y++ ) {
			int indexIn = input.startIndex + y*input.stride + 1;
			int indexOut = output.startIndex + y*output.stride + 1;

			for( int x = 1; x < input.width-1; x++ , indexIn++,indexOut++) {

				int a = 5*(input.data[indexIn] & 0xFF) - (
						(input.data[indexIn-1] & 0xFF)+(input.data[indexIn+1] & 0xFF) +
								(input.data[indexIn-input.stride] & 0xFF) + (input.data[indexIn+input.stride] & 0xFF));

				if( a > maxValue )
					a = maxValue;
				else if( a < minValue )
					a = minValue;

				output.data[indexOut] = (byte)a;
			}
		}
		//CONCURRENT_ABOVE });
	}

	public static void sharpenBorder4( GrayU8 input , GrayU8 output , int minValue , int maxValue ) {

		int b = input.height-1;
		int c = input.width-1;

		//CONCURRENT_BELOW BoofConcurrency.loopFor(0,input.width,x->{
		for( int x = 0; x < input.width; x++ ) {
			int indexTop = input.startIndex + x;
			int indexBottom = input.startIndex + b*input.stride + x;
			int value = 4*safeGet(input,x,0) - (safeGet(input,x-1,0) + safeGet(input,x+1,0) + safeGet(input,x,1));

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexTop++] = (byte)value;

			value = 4*safeGet(input,x,b) - (safeGet(input,x-1,b) + safeGet(input,x+1,b) + safeGet(input,x,b-1));

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexBottom++] = (byte)value;
		}
		//CONCURRENT_ABOVE });

		//CONCURRENT_BELOW BoofConcurrency.loopFor(1,input.height-1,y->{
		for( int y = 1; y < input.height-1; y++ ) {
			int indexLeft = input.startIndex + input.stride*y;
			int indexRight = input.startIndex + input.stride*y + c;
			int value = 4*safeGet(input,0,y) - (safeGet(input,1,y) + safeGet(input,0,y-1) + safeGet(input,0,y+1));

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexLeft] = (byte)value;

			value = 4*safeGet(input,c,y) - (safeGet(input,c-1,y) + safeGet(input,c,y-1) + safeGet(input,c,y+1));

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexRight] = (byte)value;
		}
		//CONCURRENT_ABOVE });
	}

	public static void sharpenInner4( GrayF32 input , GrayF32 output , float minValue , float maxValue ) {
		//CONCURRENT_BELOW BoofConcurrency.loopFor(1,input.height-1,y->{
		for( int y = 1; y < input.height-1; y++ ) {
			int indexIn = input.startIndex + y*input.stride + 1;
			int indexOut = output.startIndex + y*output.stride + 1;

			for( int x = 1; x < input.width-1; x++ , indexIn++,indexOut++) {

				float a = 5*(input.data[indexIn] ) - (
						(input.data[indexIn-1] )+(input.data[indexIn+1] ) +
								(input.data[indexIn-input.stride] ) + (input.data[indexIn+input.stride] ));

				if( a > maxValue )
					a = maxValue;
				else if( a < minValue )
					a = minValue;

				output.data[indexOut] = a;
			}
		}
		//CONCURRENT_ABOVE });
	}

	public static void sharpenBorder4( GrayF32 input , GrayF32 output , float minValue , float maxValue ) {

		int b = input.height-1;
		int c = input.width-1;

		//CONCURRENT_BELOW BoofConcurrency.loopFor(0,input.width,x->{
		for( int x = 0; x < input.width; x++ ) {
			int indexTop = input.startIndex + x;
			int indexBottom = input.startIndex + b*input.stride + x;
			float value = 4*safeGet(input,x,0) - (safeGet(input,x-1,0) + safeGet(input,x+1,0) + safeGet(input,x,1));

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexTop++] = value;

			value = 4*safeGet(input,x,b) - (safeGet(input,x-1,b) + safeGet(input,x+1,b) + safeGet(input,x,b-1));

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexBottom++] = value;
		}
		//CONCURRENT_ABOVE });

		//CONCURRENT_BELOW BoofConcurrency.loopFor(1,input.height-1,y->{
		for( int y = 1; y < input.height-1; y++ ) {
			int indexLeft = input.startIndex + input.stride*y;
			int indexRight = input.startIndex + input.stride*y + c;
			float value = 4*safeGet(input,0,y) - (safeGet(input,1,y) + safeGet(input,0,y-1) + safeGet(input,0,y+1));

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexLeft] = value;

			value = 4*safeGet(input,c,y) - (safeGet(input,c-1,y) + safeGet(input,c,y-1) + safeGet(input,c,y+1));

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexRight] = value;
		}
		//CONCURRENT_ABOVE });
	}

	public static void sharpenInner8( GrayU8 input , GrayU8 output , int minValue , int maxValue ) {
		//CONCURRENT_BELOW BoofConcurrency.loopFor(1,input.height-1,y->{
		for( int y = 1; y < input.height-1; y++ ) {
			int indexIn = input.startIndex + y*input.stride + 1;
			int indexOut = output.startIndex + y*output.stride + 1;

			for( int x = 1; x < input.width-1; x++ , indexIn++,indexOut++) {

				int a11 = input.data[indexIn-input.stride-1] & 0xFF;
				int a12 = input.data[indexIn-input.stride] & 0xFF;
				int a13 = input.data[indexIn-input.stride+1] & 0xFF;
				int a21 = input.data[indexIn-1] & 0xFF;
				int a22 = input.data[indexIn] & 0xFF;
				int a23 = input.data[indexIn+1] & 0xFF;
				int a31 = input.data[indexIn+input.stride-1] & 0xFF;
				int a32 = input.data[indexIn+input.stride] & 0xFF;
				int a33 = input.data[indexIn+input.stride+1] & 0xFF;
				
				int result = 9*a22 - (a11+a12+a13+a21+a23+a31+a32+a33);

				if( result > maxValue )
					result = maxValue;
				else if( result < minValue )
					result = minValue;

				output.data[indexOut] = (byte)result;
			}
		}
		//CONCURRENT_ABOVE });
	}

	public static void sharpenBorder8( GrayU8 input , GrayU8 output , int minValue , int maxValue ) {
		int b = input.height-1;
		int c = input.width-1;
		//CONCURRENT_BELOW BoofConcurrency.loopFor(0,input.width,x->{
		for( int x = 0; x < input.width; x++ ) {
			int indexTop = input.startIndex + x;
			int indexBottom = input.startIndex + x + b*input.stride;

			int a11 = safeGet(input,x-1,-1);
			int a12 = safeGet(input,x  ,-1);
			int a13 = safeGet(input,x+1,-1);
			int a21 = safeGet(input,x-1, 0);
			int a22 = safeGet(input,x  , 0);
			int a23 = safeGet(input,x+1, 0);
			int a31 = safeGet(input,x-1, 1);
			int a32 = safeGet(input,x  , 1);
			int a33 = safeGet(input,x+1, 1);

			int value = 9*a22 - (a11+a12+a13+a21+a23+a31+a32+a33);

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexTop++] = (byte)value;

			a11 = safeGet(input,x-1,b-1);
			a12 = safeGet(input,x  ,b-1);
			a13 = safeGet(input,x+1,b-1);
			a21 = safeGet(input,x-1, b);
			a22 = safeGet(input,x  , b);
			a23 = safeGet(input,x+1, b);
			a31 = safeGet(input,x-1,b+1);
			a32 = safeGet(input,x  ,b+1);
			a33 = safeGet(input,x+1,b+1);

			value = 9*a22 - (a11+a12+a13+a21+a23+a31+a32+a33);

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexBottom++] = (byte)value;
		}
		//CONCURRENT_ABOVE });

		//CONCURRENT_BELOW BoofConcurrency.loopFor(1,input.height-1,y->{
		for( int y = 1; y < input.height-1; y++ ) {
			int indexLeft = input.startIndex + input.stride*y;
			int indexRight = input.startIndex + input.stride*y + c;
			int a11 = safeGet(input,-1,y-1);
			int a12 = safeGet(input, 0,y-1);
			int a13 = safeGet(input,+1,y-1);
			int a21 = safeGet(input,-1, y );
			int a22 = safeGet(input, 0, y );
			int a23 = safeGet(input,+1, y );
			int a31 = safeGet(input,-1,y+1);
			int a32 = safeGet(input, 0,y+1);
			int a33 = safeGet(input,+1,y+1);

			int value = 9*a22 - (a11+a12+a13+a21+a23+a31+a32+a33);

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexLeft] = (byte)value;

			a11 = safeGet(input,c-1,y-1);
			a12 = safeGet(input, c ,y-1);
			a13 = safeGet(input,c+1,y-1);
			a21 = safeGet(input,c-1, y );
			a22 = safeGet(input, c , y );
			a23 = safeGet(input,c+1, y );
			a31 = safeGet(input,c-1,y+1);
			a32 = safeGet(input, c ,y+1);
			a33 = safeGet(input,c+1,y+1);

			value = 9*a22 - (a11+a12+a13+a21+a23+a31+a32+a33);

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexRight] = (byte)value;
		}
		//CONCURRENT_ABOVE });
	}

	public static void sharpenInner8( GrayF32 input , GrayF32 output , float minValue , float maxValue ) {
		//CONCURRENT_BELOW BoofConcurrency.loopFor(1,input.height-1,y->{
		for( int y = 1; y < input.height-1; y++ ) {
			int indexIn = input.startIndex + y*input.stride + 1;
			int indexOut = output.startIndex + y*output.stride + 1;

			for( int x = 1; x < input.width-1; x++ , indexIn++,indexOut++) {

				float a11 = input.data[indexIn-input.stride-1] ;
				float a12 = input.data[indexIn-input.stride] ;
				float a13 = input.data[indexIn-input.stride+1] ;
				float a21 = input.data[indexIn-1] ;
				float a22 = input.data[indexIn] ;
				float a23 = input.data[indexIn+1] ;
				float a31 = input.data[indexIn+input.stride-1] ;
				float a32 = input.data[indexIn+input.stride] ;
				float a33 = input.data[indexIn+input.stride+1] ;
				
				float result = 9*a22 - (a11+a12+a13+a21+a23+a31+a32+a33);

				if( result > maxValue )
					result = maxValue;
				else if( result < minValue )
					result = minValue;

				output.data[indexOut] = result;
			}
		}
		//CONCURRENT_ABOVE });
	}

	public static void sharpenBorder8( GrayF32 input , GrayF32 output , float minValue , float maxValue ) {
		int b = input.height-1;
		int c = input.width-1;
		//CONCURRENT_BELOW BoofConcurrency.loopFor(0,input.width,x->{
		for( int x = 0; x < input.width; x++ ) {
			int indexTop = input.startIndex + x;
			int indexBottom = input.startIndex + x + b*input.stride;

			float a11 = safeGet(input,x-1,-1);
			float a12 = safeGet(input,x  ,-1);
			float a13 = safeGet(input,x+1,-1);
			float a21 = safeGet(input,x-1, 0);
			float a22 = safeGet(input,x  , 0);
			float a23 = safeGet(input,x+1, 0);
			float a31 = safeGet(input,x-1, 1);
			float a32 = safeGet(input,x  , 1);
			float a33 = safeGet(input,x+1, 1);

			float value = 9*a22 - (a11+a12+a13+a21+a23+a31+a32+a33);

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexTop++] = value;

			a11 = safeGet(input,x-1,b-1);
			a12 = safeGet(input,x  ,b-1);
			a13 = safeGet(input,x+1,b-1);
			a21 = safeGet(input,x-1, b);
			a22 = safeGet(input,x  , b);
			a23 = safeGet(input,x+1, b);
			a31 = safeGet(input,x-1,b+1);
			a32 = safeGet(input,x  ,b+1);
			a33 = safeGet(input,x+1,b+1);

			value = 9*a22 - (a11+a12+a13+a21+a23+a31+a32+a33);

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexBottom++] = value;
		}
		//CONCURRENT_ABOVE });

		//CONCURRENT_BELOW BoofConcurrency.loopFor(1,input.height-1,y->{
		for( int y = 1; y < input.height-1; y++ ) {
			int indexLeft = input.startIndex + input.stride*y;
			int indexRight = input.startIndex + input.stride*y + c;
			float a11 = safeGet(input,-1,y-1);
			float a12 = safeGet(input, 0,y-1);
			float a13 = safeGet(input,+1,y-1);
			float a21 = safeGet(input,-1, y );
			float a22 = safeGet(input, 0, y );
			float a23 = safeGet(input,+1, y );
			float a31 = safeGet(input,-1,y+1);
			float a32 = safeGet(input, 0,y+1);
			float a33 = safeGet(input,+1,y+1);

			float value = 9*a22 - (a11+a12+a13+a21+a23+a31+a32+a33);

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexLeft] = value;

			a11 = safeGet(input,c-1,y-1);
			a12 = safeGet(input, c ,y-1);
			a13 = safeGet(input,c+1,y-1);
			a21 = safeGet(input,c-1, y );
			a22 = safeGet(input, c , y );
			a23 = safeGet(input,c+1, y );
			a31 = safeGet(input,c-1,y+1);
			a32 = safeGet(input, c ,y+1);
			a33 = safeGet(input,c+1,y+1);

			value = 9*a22 - (a11+a12+a13+a21+a23+a31+a32+a33);

			if( value > maxValue )
				value = maxValue;
			else if( value < minValue )
				value = minValue;

			output.data[indexRight] = value;
		}
		//CONCURRENT_ABOVE });
	}

	/**
	 * Handle outside image pixels by extending the image.
	 */
	public static int safeGet( GrayI input , int x , int y ) {
		if( x < 0 )
			x = 0;
		else if( x >= input.width )
			x = input.width-1;
		if( y < 0 )
			y = 0;
		else if( y >= input.height )
			y = input.height-1;

		return input.unsafe_get(x,y);
	}

	/**
	 * Handle outside image pixels by extending the image.
	 */
	public static float safeGet( GrayF32 input , int x , int y ) {
		if( x < 0 )
			x = 0;
		else if( x >= input.width )
			x = input.width-1;
		if( y < 0 )
			y = 0;
		else if( y >= input.height )
			y = input.height-1;

		return input.unsafe_get(x,y);
	}

}
